package fr.lip6.meta.tools;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;


import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Generalization;
import org.eclipse.uml2.uml.Message;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.internal.impl.ClassImpl;
import org.eclipse.uml2.uml.internal.impl.PackageImpl;

import fr.lip6.meta.ple.plextraction.Artefact2File;


import artefact.generic.Artefact;
import artefact.generic.ConstructionPrimitive;

import artefact.umlClassDiagram.ClassDiagram;
import artefact.umlClassDiagram.CreateAttribute;
import artefact.umlClassDiagram.CreateClass;
import artefact.umlClassDiagram.CreateOperation;
import artefact.umlClassDiagram.CreateOperationRefinement;
import artefact.umlClassDiagram.CreatePackage;
import artefact.umlClassDiagram.impl.UmlClassDiagramFactoryImpl;



@SuppressWarnings("restriction")
public class SequenceConstructionGenerator {


	Artefact artefact; 
	boolean first = false;

	ConstructionPrimitive currentPrimitive=null;


	FileWriter fw = null;
	String projectRep = "/Users/ziadi/DONNEES/ACTIVITIES-DEVELOPEMENT/Eclipse-WorkSpaces/FeatureID/Z.SPL/"; /* METTRE REPERTOIRE DU PROJET */
	String modelRep = projectRep+"model/";
	String generatedRep = projectRep+"generated/";
	String variablescom = "\n<!-- VARIABLE DEFINITIONS ETC -->\n\n";
	String bodycom = "\n<!-- MAIN EXECUTION -->\n\n";
	HashMap<Message,String> conditions = new HashMap<Message,String>();


	/* Ces chaînes vont contenir les différents bouts de code avant de les écrire dans le fichier dans le bon ordre */
	public String head = "";
	public String links = "";
	public String variables = "";
	public String body = "";
	public String tail = "";


	UmlClassDiagramFactoryImpl factory;
	ClassDiagram product;
	public static int indent = 0;


	/* Constructor */
	public SequenceConstructionGenerator(){
		factory = new UmlClassDiagramFactoryImpl();
		product = factory.createClassDiagram();
	}


	/* Gestion d'indentations pour l'affichage */
	public String getindent(){
		String res="";
		for (int i=0; i<indent; i++){
			res += " ";
		}
		return res;
	}
	
	public String getindent(int n){
		String res="";
		for (int i=0; i<n; i++){
			res += " ";
		}
		return res;
	}


	/* This function generates a BPEL file */
	public void generate(List<EObject> model) throws IOException{


		EObject pe;
		/* Creation d'un fichier avec comme nom le nom du modèle (on suppose qu'il est premier dans la liste) */
		fw = new FileWriter("sequence.seq");

		Iterator<EObject> i12 = model.iterator();
		UmlClassDiagramFactoryImpl factory = new UmlClassDiagramFactoryImpl();
		/*ClassDiagram productCD1 = */factory.createClassDiagram();

		System.out.println("TAILLE :"+model.size() );
		while (i12.hasNext()){
			pe = i12.next();
			//System.out.println("TRAITEMENT ELEMENT :"+pe.getClass().getName());
			//System.out.println("List gives : " + pe.getClass().getName());


			/* IF MODEL */
			if (pe.getClass().getName() == "org.eclipse.uml2.uml.internal.impl.ModelImpl"){
				head += "! Sequence construction :\"" + ((Model)pe).getName() + "\"\n";
			}


			/* IF Package */
			if (pe.getClass().getName() == "org.eclipse.uml2.uml.internal.impl.PackageImpl"){

				PackageImpl pei =(PackageImpl)pe;
				if (!((pei.getName().contains("Common Java")  || (pei.getName().contains("java")) || 
						(pei.getName().contains("lang"))
						|| (pei.getName().contains("io")) || 
						(pei.getName().contains("util"))  || (pei.getName().contains("lang")))))   {
					this.generatePackage((PackageImpl)pe);

				}
			}


		} //fin boucle


		/* ON VA PARCOURIR LES OBJETS DE LA LIFELINE "APPLICATION" POUR OBTENIR LA SEQUENCE D'ACTIONS A EXECUTER */

		System.out.println("Generation complete");
		Artefact2File.print(product, "PRODUCT");
	}
	
	private void generatePackage(PackageImpl p) throws IOException{


		//System.out.println("Createpackage("+p.getName()+");");
		fw.write("Createpackage("+p.getName()+");");
		//pour chaque classes generateClass
		CreatePackage createPackage = factory.createCreatePackage();
		createPackage.setName(p.getName());
		if (currentPrimitive==null){
			currentPrimitive=createPackage;
			product.setFirst(createPackage) ; 
			System.out.println("first");

		}

		else {
			currentPrimitive.setNext(createPackage);
			currentPrimitive=createPackage;
		}

		EList<Element> classes = p.getOwnedElements();


		for (Element e:classes){
			if (e.getClass().getName()=="org.eclipse.uml2.uml.internal.impl.ClassImpl"){
				ClassImpl ci = (ClassImpl)e;
				if(!((ci.getName().contains("ArrayList")  || (ci.getName().contains("AbstractCollection"))))  || 
						(ci.getName().contains("String")) || (ci.getName().contains("AbstractList"))  ){
					this.generateClass((ClassImpl)e, p);
				}
			}
		}
	}
	
	private void generateClass(ClassImpl c, PackageImpl p) throws IOException{
		//	if (c.getName().contains("$$")) return;
		//System.out.println("CreateClass("+c.getName()+","+p.getName()+")");
		String ownerBasic=p.getName();
		boolean doll = false;


		if (c.getName().contains("$$")){

			doll = true;
			int index= c.getName().indexOf("$$"); 
			if (index >0) {
				ownerBasic = c.getName().substring(0, index); 
				//System.out.println("$$ found at :"+index + "==> "+ownerBasic);
			}
		}
		if (!doll){ 

			fw.write("CreateClass("+c.getName()+","+ownerBasic+")");
			CreateClass createClass = factory.createCreateClass();
			createClass.setName(c.getName());
			createClass.setOwener(ownerBasic);
			if (currentPrimitive==null){
				currentPrimitive=createClass;
				product.setFirst(createClass) ;

				System.out.println("first");
			}

			else {
				currentPrimitive.setNext(createClass);
				currentPrimitive=createClass;
			}

		}
		// pour chaque attribut : generateAttribut
		EList<Property> properties = c.getAttributes();
		//
		for (Property pp: properties){
			this.generateAttribute(pp, c);
		}


		//pour chaque op�ration : generateC
		EList<Operation> operations = c.getOperations();
		for (Operation op: operations){
			this.generateOperation(op, c);
		}
	}
	
	private void generateAttribute(Property a, ClassImpl owner) throws IOException{

		//System.out.println("CreareAttribute("+a.getName()+"," +owner.getName()+")");
		String ownerBasic=owner.getName();
		if (owner.getName().contains("$$")){
			int index= owner.getName().indexOf("$$"); 
			if (index >0) {
				ownerBasic = owner.getName().substring(0, index); 
				//System.out.println("$$ found at :"+index + "==> "+ownerBasic);
			}
		}
		fw.write("CreareAttribute("+a.getName()+"," +ownerBasic+")");
		CreateAttribute createAttribute = factory.createCreateAttribute();
		createAttribute.setName(getBasic(a.getName()));
		createAttribute.setOwner(ownerBasic);

		if(a.getUpper()==-1) 
			createAttribute.setType(a.getType().getName()+"[]");
		else 	createAttribute.setType(a.getType().getName());

		if (currentPrimitive==null){
			currentPrimitive=createAttribute;
			product.setFirst(createAttribute) ;  
		}

		else {
			currentPrimitive.setNext(createAttribute);
			currentPrimitive=createAttribute;
		}
	}
	
	private void generateOperation(Operation o, ClassImpl owner) throws IOException{

		if(this.checkOperationrefinement(o, owner)){



			//System.out.println("CreateOperationRefinement("+o.getName()+","+owner.getName());

			fw.write("CreateOperationRefinement("+o.getName()+","+owner);
			CreateOperationRefinement createOperationRef = factory.createCreateOperationRefinement();
			createOperationRef.setName(getBasic(o.getName()));
			createOperationRef.setOwner(owner.getName());
			if (currentPrimitive==null){
				currentPrimitive=createOperationRef;
				product.setFirst(createOperationRef) ;  
			}

			else {


				currentPrimitive.setNext(createOperationRef);
				currentPrimitive=createOperationRef;
			}




		}

		else {
			//System.out.println("CreateOperation("+o.getName()+","+owner.getName());
			String ownerBasic=owner.getName();
			if (owner.getName().contains("$$")){
				int index= owner.getName().indexOf("$$"); 
				if (index >0) {
					ownerBasic = owner.getName().substring(0, index); 
					System.out.println("$$ found at :"+index + "==> "+ownerBasic);
				}
			}
			fw.write("CreateOperation("+o.getName()+","+ownerBasic);
			CreateOperation createOperation = factory.createCreateOperation();
			createOperation.setName(getBasic(o.getName()));
			createOperation.setOwener(ownerBasic);
			if (currentPrimitive==null){
				currentPrimitive=createOperation;
				product.setFirst(createOperation) ;  
			}

			else {
				currentPrimitive.setNext(createOperation);
				currentPrimitive=createOperation;
			}

		}      

	}

	private String getBasic(String s) {
		if (s.contains("$$")){
			int index= s.indexOf("$$"); 
			if (index >0)
				return s.substring(0, index); 
		}
		return s;
	}

	public ClassDiagram getProduct() {
		return product;
	}


	public void setProduct(ClassDiagram product) {
		this.product = product;
	}


	private boolean checkOperationrefinement(Operation o, ClassImpl owner){

		boolean result = false;
		EList<Generalization> gens =owner.getGeneralizations();

		for(Generalization g:gens){

			Classifier cf = g.getGeneral();

			if (cf.getClass().getName()=="org.eclipse.uml2.uml.internal.impl.ClassImpl"){
				ClassImpl ci = (ClassImpl)cf;
				for( Operation oo:ci.getAllOperations()){

					if (oo.getName().equals(o.getName())){
						return true;
					}
				}
			}
		}

		return result;
	}

}
